#pragma once
#include <iostream>
#include <memory>
#include <functional>
#include <pthread.h>
#include <unistd.h>
#include "Socket.hpp"
using namespace std;

using func_t = function<void(int)>;

class TcpServer;

class ThreadData
{
public:
    ThreadData(TcpServer *server_ptr, Socket *sock) : _this(server_ptr), _sock(sock)
    {
    }

    ~ThreadData()
    {
        delete (_sock);
        // cout << "delete _sock: " << _sock << endl;
    }

public:
    TcpServer *_this;
    Socket *_sock;
};

class TcpServer
{
private:
    static void *ThreadRun(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(args);
        td->_this->_func(td->_sock->GetSockFd());

        td->_sock->CloseFd(true);
        delete td;
        // cout << "delete td: " << td << endl;

        return nullptr;
    }

public:
    TcpServer(int port, func_t func) : _port(port), _func(func)
    {
    }

    void Loop()
    {
        unique_ptr<Socket> up(new TcpSocket(_port));
        up->BuildTcpServer(5);
        while (true)
        {
            Socket *sock = up->AcceptSockFd();

            pthread_t tid;
            ThreadData *td = new ThreadData(this, sock);
            // cout << "new td: " << td << endl;
            pthread_create(&tid, nullptr, ThreadRun, td);
        }
        up->CloseFd(false);
    }

    ~TcpServer()
    {
    }

private:
    int _port;
    func_t _func;
};
